package com.nimble.smile.activity;

import android.app.AlertDialog;
import android.content.DialogInterface;
import android.graphics.Bitmap;
import android.graphics.SurfaceTexture;
import android.hardware.usb.UsbDevice;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Surface;
import android.view.View;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;

import com.nimble.smile.R;
import com.nimble.smile.service.vo.ImageDTO;
import com.nimble.smile.service.OperationCode;
import com.nimble.smile.service.ResponseEntityBody;
import com.nimble.smile.service.ServiceManager;
import com.nimble.smile.utils.SharedPreferenceHelper;
import com.nimble.smile.utils.UIHelper;
import com.nimble.smile.widget.SimpleUVCCameraTextureView;
import com.qiniu.android.common.Zone;
import com.qiniu.android.http.ResponseInfo;
import com.qiniu.android.storage.Configuration;
import com.qiniu.android.storage.UploadManager;
import com.serenegiant.usb.USBMonitor;
import com.serenegiant.usb.USBMonitor.OnDeviceConnectListener;
import com.serenegiant.usb.USBMonitor.UsbControlBlock;
import com.serenegiant.usb.UVCCamera;
import com.squareup.picasso.Callback;
import com.squareup.picasso.Picasso;

import java.io.ByteArrayOutputStream;
import java.util.UUID;

import butterknife.ButterKnife;
import rx.Observable;
import rx.schedulers.Schedulers;

public final class TakePhotoActivity extends BaseActivity implements View.OnClickListener {

    private static final int PREVIEW_WIDTH = 720;
    private static final int PREVIEW_HEIGHT = 480;

    //private final Object mSync = new Object();
    // for accessing USB and USB camera
    private USBMonitor mUSBMonitor;
    private UVCCamera mUVCCamera;
    private SimpleUVCCameraTextureView mUVCCameraView;
    // for open&start / stop&close camera preview
    private Surface mPreviewSurface;
    private String imageKey;

    @Override
    protected void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_photo);

        findViewById(R.id.take_photo).setOnClickListener(this);

        mUVCCameraView = (SimpleUVCCameraTextureView)findViewById(R.id.UVCCameraTextureView1);
        mUVCCameraView.setAspectRatio(UVCCamera.DEFAULT_PREVIEW_WIDTH / (float) UVCCamera.DEFAULT_PREVIEW_HEIGHT);

        mUSBMonitor = new USBMonitor(this, mOnDeviceConnectListener);

        showProgressDialog("查找设备...");
    }

    @Override
    protected void onStart() {
        super.onStart();
        mUSBMonitor.register();
        if (mUVCCamera != null) {
            mUVCCamera.setPreviewSize(PREVIEW_WIDTH, PREVIEW_HEIGHT);
            mUVCCamera.startPreview();
        }
    }

    @Override
    protected void onStop() {
        super.onStop();
        if (mUVCCamera != null) {
            mUVCCamera.stopPreview();
        }
        if (mUSBMonitor != null) {
            mUSBMonitor.unregister();
        }
    }

    @Override
    protected void onDestroy() {
        releaseCamera();
        if (mUSBMonitor != null) {
            mUSBMonitor.destroy();
            mUSBMonitor = null;
        }
        super.onDestroy();
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.take_photo:
                takePhoto();
                break;
        }

    }

    private void takePhoto() {
        showProgressDialog("处理中...");
        Observable<ResponseEntityBody<Double>> responseObservable = Observable.zip(
                uploadTokeObservable(),
                getImageObservable(),
                (response, data) -> new UploadObject(response.getBody(), data))
                .flatMap(this::uploadObservable)
                .flatMap(this::getHappinessObservable);

        subscribe(responseObservable, response -> {
            hideProgressDialog();
            if (response.getOperationCode() == OperationCode.SUCCESS.getValue()) {
                this.showResult(this.imageKey, response.getBody());
            } else {
                showToast(response.getMessage());
            }
        });
    }

    private Observable<ResponseEntityBody<String>> uploadTokeObservable() {
        return ServiceManager.getInstance().getService().getToken().subscribeOn(Schedulers.io());
    }

    private Observable<ResponseEntityBody<Double>> getHappinessObservable(String key) {
        ImageDTO image = new ImageDTO();
        image.setImg(key);
        this.imageKey = key;
        return ServiceManager.getInstance().getService().getHappiness(image);
    }

    private Observable<byte[]> getImageObservable() {
        return Observable.create(subscriber -> {
            Bitmap bm = mUVCCameraView.getBitmap();
            int width = bm.getWidth();
            int height = bm.getHeight();
            int scaleWidth = width / 2;
            int scaleHeight = height / 2;

            Bitmap resizedBitmap = Bitmap.createScaledBitmap(bm, scaleWidth, scaleHeight, false);
            bm.recycle();
            ByteArrayOutputStream stream = new ByteArrayOutputStream();
            resizedBitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);

            subscriber.onNext(stream.toByteArray());
            subscriber.onCompleted();
        });
    }

    private Observable<String> uploadObservable(UploadObject uploadObject) {
        String mobile = SharedPreferenceHelper.getSharedPreferenceString("mobile", "default");
        String key = String.format("smile/%s/%s.jpg", mobile, UUID.randomUUID());

        Configuration config = new Configuration.Builder()
                .chunkSize(256 * 1024)  //分片上传时，每片的大小。 默认256K
                .putThreshhold(512 * 1024)  // 启用分片上传阀值。默认512K
                .connectTimeout(10) // 链接超时。默认10秒
                .responseTimeout(60) // 服务器响应超时。默认60秒
                .zone(Zone.zone0) // 设置区域，指定不同区域的上传域名、备用域名、备用IP。
                .build();
        UploadManager uploadManager = new UploadManager(config);

        return Observable.create(subscriber -> {
            ResponseInfo info = uploadManager.syncPut(uploadObject.data, key, uploadObject.token, null);
            if (info.isOK()) {
                subscriber.onNext(key);
                subscriber.onCompleted();
            } else {
                subscriber.onError(new Exception(info.toString()));
            }

        });
    }

    private void showResult(String key, double score) {
        View view = LayoutInflater.from(this).inflate(R.layout.view_photo, null, false);
        ImageView imageView = ButterKnife.findById(view, R.id.image);
        TextView scoreView = ButterKnife.findById(view, R.id.score);
        View imageContainer = ButterKnife.findById(view, R.id.image_container);
        ProgressBar progressBar = ButterKnife.findById(view, R.id.progress);
        scoreView.setText(String.valueOf(score));

        new AlertDialog.Builder(this, AlertDialog.THEME_DEVICE_DEFAULT_DARK)
                .setTitle("微笑分数")
                .setView(view)
                .setNegativeButton("重拍", null)
                .setPositiveButton("退出", (dialog, which) -> logout())
                .show();

        Picasso.with(this)
                .load("http://kanken.mynimble.cn/" + key)
                .placeholder(R.mipmap.photo_preview_holder)
                .resizeDimen(R.dimen.image_preview_size, R.dimen.image_preview_size)
                .centerInside()
                .into(imageView, new Callback() {
                    @Override
                    public void onSuccess() {
                        imageContainer.setVisibility(View.VISIBLE);
                        progressBar.setVisibility(View.GONE);
                    }

                    @Override
                    public void onError() {

                    }
                });
    }

    private void logout() {
        LoginActivity.backWithClearTop(this);
    }

    //private Toast mToast;

    private final OnDeviceConnectListener mOnDeviceConnectListener = new OnDeviceConnectListener() {

        @Override
        public void onConnect(final UsbDevice device, final UsbControlBlock ctrlBlock, final boolean createNew) {
            releaseCamera();
            mUVCCameraView.post(() -> {
                final UVCCamera camera = new UVCCamera();
                camera.open(ctrlBlock);

                if (mPreviewSurface != null) {
                    mPreviewSurface.release();
                    mPreviewSurface = null;
                }

                try {
                    camera.setPreviewSize(PREVIEW_WIDTH, PREVIEW_HEIGHT, UVCCamera.FRAME_FORMAT_MJPEG);
                } catch (final IllegalArgumentException e) {
                    // fallback to YUV mode
                    try {
                        camera.setPreviewSize(UVCCamera.DEFAULT_PREVIEW_WIDTH, UVCCamera.DEFAULT_PREVIEW_HEIGHT, UVCCamera.FRAME_FORMAT_YUYV);
                    } catch (final IllegalArgumentException e1) {
                        camera.destroy();
                        return;
                    }
                }

                final SurfaceTexture st = mUVCCameraView.getSurfaceTexture();
                if (st != null) {
                    mPreviewSurface = new Surface(st);
                    camera.setPreviewDisplay(mPreviewSurface);
                    camera.startPreview();
                }
                mUVCCamera = camera;
            });
        }

        @Override
        public void onDisconnect(final UsbDevice device, final UsbControlBlock ctrlBlock) {
            releaseCamera();
        }

        @Override
        public void onDettach(final UsbDevice device) {
            //Toast.makeText(TakePhotoActivity.this, "USB_DEVICE_DETACHED", Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onCancel(final UsbDevice device) {
        }

        @Override
        public void onAttach(final UsbDevice device) {
            //Toast.makeText(TakePhotoActivity.this, "USB_DEVICE_ATTACHED", Toast.LENGTH_SHORT).show();
            mUSBMonitor.requestPermission(device);
            UIHelper.getInstance().hideProgressDialog();
        }
    };

    private void releaseCamera() {
        if (mUVCCamera != null) {
            try {
                mUVCCamera.setStatusCallback(null);
                mUVCCamera.setButtonCallback(null);
                mUVCCamera.close();
                mUVCCamera.destroy();
            } catch (final Exception e) {
                //
            }
            mUVCCamera = null;
        }
        if (mPreviewSurface != null) {
            mPreviewSurface.release();
            mPreviewSurface = null;
        }
    }

    static class UploadObject {
        public UploadObject(String token, byte[] data) {
            this.token = token;
            this.data = data;
        }
        public String token;
        public byte[] data;
    }
}
